#ifndef AABB_HPP
# define AABB_HPP

#include "vector.hpp"

template <typename T, ::std::size_t N>
using aabb_type = struct { ::etl::vector<T, N> a; ::etl::vector<T, N> b; };

// AABB transformations
template <class M, typename T, ::std::size_t N>
inline aabb_type<T, N> tr_cr_aabb(M const& matrix,
  aabb_type<T, N> const& aabb)
{
  static_assert(M::rows == M::cols);

  aabb_type r;

  for (typename M::size_type i{}; i != M::rows - 1; ++i)
  {
    r.a(i) = matrix(i, M::cols - 1);
    r.b(i) = T{};

    for (typename M::size_type j{}; j != M::cols - 1; ++j)
    {
      r.a(i) += matrix(i, j) * aabb.a(j);
      r.b(i) += ::std::abs(matrix(i, j)) * aabb.b(j);
    }
  }

  return r;
}

template <::std::size_t V, class M, typename T, ::std::size_t N>
inline typename ::std::enable_if<
  0 == V,
  aabb_type<T, N>
>::type
tr_cr_aabb(M const& matrix, aabb_type<T, N> const& aabb)
{
  static_assert(M::rows == M::cols);

  aabb_type r;

  for (typename M::size_type i{}; i != M::rows - 1; ++i)
  {
    r.a(i) = r.b(i) = T{};

    for (typename M::size_type j{}; j != M::cols - 1; ++j)
    {
      r.a(i) += matrix(i, j) * aabb.a(j);
      r.b(i) += ::std::abs(matrix(i, j)) * aabb.b(j);
    }
  }

  return r;
}

#endif // AABB_HPP
